package com.cdck.safe.dete.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cdck.safe.dete.common.exception.BusinessException;
import com.cdck.safe.dete.common.util.SecurityUtils;
import com.cdck.safe.dete.mapper.BookRecordMapper;
import com.cdck.safe.dete.model.entity.*;
import com.cdck.safe.dete.mapper.BookingMapper;
import com.cdck.safe.dete.model.query.BaseKeywordsQuery;
import com.cdck.safe.dete.model.vo.BookingVO;
import com.cdck.safe.dete.security.userdetails.SysUserDetails;
import com.cdck.safe.dete.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;

import javax.annotation.Resource;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (Booking)表服务实现类
 *
 * @author wp
 * @since 2024-02-25 16:43:26
 */
@Service
@RequiredArgsConstructor
public class BookingServiceImpl extends ServiceImpl<BookingMapper, Booking> implements BookingService {
    @Resource
    private SysUserService userService;

    @Resource
    private LaboratoryService laboratoryService;

    @Resource
    private SeatService seatService;

    @Resource
    private BookRecordMapper bookRecordMapper;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public Booking getBookingFormData(Long id) {
        return this.getById(id);
    }

    /**
     * 分页查询
     * <p>
     * queryParams 筛选条件
     *
     * @return 查询结果
     */
    @Override
    public IPage<BookingVO> queryByPage(BaseKeywordsQuery queryParams) {
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        String keywords = queryParams.getKeywords();
        List<Long> userIds = new ArrayList<>();
        List<Long> labIds = new ArrayList<>();

        if (StrUtil.isNotBlank(keywords)) {
            //用户姓名
            LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.like(SysUser::getNickname, keywords);
            List<SysUser> sysUserList = userService.list(userWrapper);
            userIds = sysUserList.stream().map(item -> item.getId()).collect(Collectors.toList());
            //实验室编号 或者用户的预约
            LambdaQueryWrapper<Laboratory> labWrapper = new LambdaQueryWrapper<>();
            labWrapper.like(Laboratory::getLabNo, keywords);
            List<Laboratory> laboratoryList = laboratoryService.list(labWrapper);
            labIds = laboratoryList.stream().map(item -> item.getId()).collect(Collectors.toList());
        }
        Page<Booking> page = new Page<>(pageNum, pageSize);
        Page<BookingVO> pageVO = new Page<>(pageNum, pageSize);
        //都为null则返回空，否则返回查询到的数据
        if (StrUtil.isNotBlank(keywords) && userIds.size() == 0 && labIds.size() == 0) {
            return pageVO;
        }
        LambdaQueryWrapper<Booking> queryWrapper = new LambdaQueryWrapper<Booking>();
        if (StrUtil.isNotBlank(keywords) && labIds.size() > 0) {
            queryWrapper.in(Booking::getLabId, labIds);
        }
        if (StrUtil.isNotBlank(keywords) && userIds.size() > 0) {
            queryWrapper.or().in(Booking::getUserId, userIds);
        }

        Page<Booking> bookingPage = this.page(
                page,
                queryWrapper
        );
        List<BookingVO> bookingVOList = bookingPage.getRecords().stream().map(item -> {
            BookingVO vo = new BookingVO();
            BeanUtils.copyProperties(item, vo);
            Laboratory laboratory = laboratoryService.getById(item.getLabId());
            if (!BeanUtil.isEmpty(laboratory)) {
                vo.setLabName(laboratory.getName());
            }

            Seat seat = seatService.getById(item.getSeatId());
            if (!BeanUtil.isEmpty(seat)) {
                vo.setSeatNo(seat.getSeatNo());
            }

            SysUser sysUser = userService.getById(item.getUserId());
            if (!BeanUtil.isEmpty(sysUser)) {
                vo.setBookUser(sysUser.getNickname());
            }

            return vo;
        }).collect(Collectors.toList());
        BeanUtils.copyProperties(bookingPage, pageVO, "records");
        pageVO.setRecords(bookingVOList);
        return pageVO;
    }

    /**
     * 新增数据
     *
     * @param booking 实例对象
     * @return 实例对象
     */
    @Transactional
    @Override
    public boolean saveBooking(Booking booking) {
        //springSecurity获取当前登录的用户信息
        SysUserDetails user = SecurityUtils.getUser();
        booking.setUserId(user.getUserId());
        booking.setStatus(0);
        this.save(booking);
        BookRecord record = new BookRecord();
        record.setBookId(booking.getId());
        return bookRecordMapper.insert(record) > 0;
    }

    /**
     * 修改数据
     *
     * @param booking 实例对象
     * @return 实例对象
     */
    @Override
    public boolean updateBooking(Long id, Booking booking) {
        return this.updateById(booking);
    }

    /**
     * 通过主键删除数据
     *
     * @param idsStr ids集合
     * @return 是否成功
     */
    @Override
    public boolean deleteBookings(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的数据为空");
        // 逻辑删除
        List<Long> ids = Arrays.stream(idsStr.split(","))
                .map(Long::parseLong).collect(Collectors.toList());
        return this.removeByIds(ids);
    }

    @Override
    public IPage<BookingVO> getApplicationPage(BaseKeywordsQuery queryParams) {
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        String keywords = queryParams.getKeywords();
        List<Long> userIds = new ArrayList<>();
        List<Long> labIds = new ArrayList<>();

        if (StrUtil.isNotBlank(keywords)) {
            //用户姓名
            LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.like(SysUser::getNickname, keywords);
            List<SysUser> sysUserList = userService.list(userWrapper);
            userIds = sysUserList.stream().map(item -> item.getId()).collect(Collectors.toList());
            //实验室编号 或者用户的预约
            LambdaQueryWrapper<Laboratory> labWrapper = new LambdaQueryWrapper<>();
            labWrapper.like(Laboratory::getLabNo, keywords);
            List<Laboratory> laboratoryList = laboratoryService.list(labWrapper);
            labIds = laboratoryList.stream().map(item -> item.getId()).collect(Collectors.toList());
        }
        Page<Booking> page = new Page<>(pageNum, pageSize);
        Page<BookingVO> pageVO = new Page<>(pageNum, pageSize);
        //都为null则返回空，否则返回查询到的数据
        if (StrUtil.isNotBlank(keywords) && userIds.size() == 0 && labIds.size() == 0) {
            return pageVO;
        }
        LambdaQueryWrapper<Booking> queryWrapper = new LambdaQueryWrapper<Booking>();
        if (StrUtil.isNotBlank(keywords) && labIds.size() > 0) {
            queryWrapper.in(Booking::getLabId, labIds);
        }
        if (StrUtil.isNotBlank(keywords) && userIds.size() > 0) {
            queryWrapper.or().in(Booking::getUserId, userIds);
        }
        queryWrapper.eq(Booking::getStatus, 0);

        Page<Booking> bookingPage = this.page(
                page,
                queryWrapper
        );
        List<BookingVO> bookingVOList = bookingPage.getRecords().stream().map(item -> {
            BookingVO vo = new BookingVO();
            BeanUtils.copyProperties(item, vo);
            Laboratory laboratory = laboratoryService.getById(item.getLabId());
            if (!BeanUtil.isEmpty(laboratory)) {
                vo.setLabName(laboratory.getName());
            }

            Seat seat = seatService.getById(item.getSeatId());
            if (!BeanUtil.isEmpty(seat)) {
                vo.setSeatNo(seat.getSeatNo());
            }

            SysUser sysUser = userService.getById(item.getUserId());
            if (!BeanUtil.isEmpty(sysUser)) {
                vo.setBookUser(sysUser.getNickname());
            }

            return vo;
        }).collect(Collectors.toList());
        BeanUtils.copyProperties(bookingPage, pageVO, "records");
        pageVO.setRecords(bookingVOList);
        return pageVO;

    }

    @Override
    public boolean overrule(Booking booking) {
        booking.setStatus(1);
        return this.updateById(booking);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean pass(Long id) {
        Booking booking = this.getById(id);
        if (booking != null) {

            //查找这个作座位的所有预约记录
            LambdaQueryWrapper<Booking> bookingWrapper = new LambdaQueryWrapper<>();
            bookingWrapper
                    .eq(Booking::getLabId, booking.getLabId())
                    .eq(Booking::getStatus, 2)
                    .eq(Booking::getSeatId, booking.getId())
                    .gt(Booking::getBookEndTime, LocalDateTime.now());
            List<Booking> bookingList = this.list(bookingWrapper);
            if (bookingList == null && bookingList.size() == 0) {
                //没有预约记录，直接返回
                booking.setStatus(2);
            }
            Boolean flag = true;
            for (Booking bookingE : bookingList) {
                //如果这个时间段，记录表里面有记录，且在使用范围，说明作为被占用
                long bookingStartTime = bookingE.getBookStartTime().getTime();
                long bookingEndTime = bookingE.getBookEndTime().getTime();
                long seatStartTime = booking.getBookStartTime().getTime();
                long seatEndTime = booking.getBookEndTime().getTime();

                // 检查预订与座位时间范围是否有交叉,三种情况
                if ((seatStartTime >= bookingStartTime && seatEndTime <= bookingEndTime)
                        || (seatStartTime <= bookingStartTime && seatEndTime >= bookingStartTime)
                        || (seatStartTime <= bookingEndTime && seatEndTime >= bookingEndTime)) {
                    flag = false;
                    throw new BusinessException("该座位在该时间段已被占用");
                }
            }
            if (flag) {
                booking.setStatus(2);
            }
            return this.updateById(booking);
        }
        return false;
    }

    @Override
    public boolean cancel(Long id) {
        Booking booking = this.getById(id);
        if (booking != null) {
            booking.setStatus(4);
            return this.updateById(booking);
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean finish(Long id) {

        // 修改对应记录完成时间
        BookRecord bookRecord = bookRecordMapper.selectOne(new LambdaQueryWrapper<BookRecord>()
                .eq(BookRecord::getBookId, id));
        bookRecord.setRealEndTime(new Date());
        bookRecordMapper.updateById(bookRecord);
        Booking booking = this.getById(id);
        if (booking != null) {
            booking.setStatus(3);
            return this.updateById(booking);
        }
        return false;
    }
}
